﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Framework;

using Moq;

namespace Microsoft.Testing.Platform.MSBuild.UnitTests;

[TestClass]
public sealed class MSBuildTests
{
    private readonly Mock<IBuildEngine> _buildEngine = new();
    private readonly List<BuildErrorEventArgs> _errors = [];

    public MSBuildTests() =>
        _buildEngine.Setup(x => x.LogErrorEvent(It.IsAny<BuildErrorEventArgs>())).Callback<BuildErrorEventArgs>(e => _errors.Add(e));

    [TestMethod]
    public void Verify_Correct_Registration_Order_For_WellKnown_Extensions()
    {
        InMemoryFileSystem inMemoryFileSystem = new();
        TestingPlatformEntryPointTask testingPlatformEntryPoint = new(inMemoryFileSystem)
        {
            BuildEngine = _buildEngine.Object,
            TestingPlatformEntryPointSourcePath = new CustomTaskItem("obj/entryPointFile"),
            Language = new CustomTaskItem("C#"),
            RootNamespace = "SomeNamespace",
        };

        testingPlatformEntryPoint.Execute();

        string expectedSourceOrder = """
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

namespace SomeNamespace
{
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    internal sealed class MicrosoftTestingPlatformEntryPoint
    {
        public static async global::System.Threading.Tasks.Task<int> Main(string[] args)
        {
            global::Microsoft.Testing.Platform.Builder.ITestApplicationBuilder builder = await global::Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync(args);
            SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args);
            using (global::Microsoft.Testing.Platform.Builder.ITestApplication app = await builder.BuildAsync())
            {
                return await app.RunAsync();
            }
        }
    }
}
""";

        Assert.AreEqual(expectedSourceOrder, inMemoryFileSystem.Files["obj/entryPointFile"]);
        Assert.IsEmpty(_errors);
    }

    private sealed class InMemoryFileSystem : IFileSystem
    {
        public Dictionary<string, string?> Files { get; } = [];

        public void CopyFile(string source, string destination) => throw new NotImplementedException();

        public void CreateDirectory(string directory) => throw new NotImplementedException();

        public Stream CreateNew(string path) => throw new NotImplementedException();

        public bool Exist(string path) => Files.ContainsKey(path);

        public void WriteAllText(string path, string? contents) => Files.Add(path, contents);
    }

    private sealed class CustomTaskItem : ITaskItem
    {
        private readonly Dictionary<string, string> _keyValuePairs = [];

        public CustomTaskItem(string itemSpec) => ItemSpec = itemSpec;

        public CustomTaskItem Add(string key, string value)
        {
            _keyValuePairs[key] = value;
            return this;
        }

        public string ItemSpec { get; set; }

        public ICollection MetadataNames => throw new NotImplementedException();

        public int MetadataCount => _keyValuePairs.Count;

        public IDictionary CloneCustomMetadata() => throw new NotImplementedException();

        public void CopyMetadataTo(ITaskItem destinationItem) => throw new NotImplementedException();

        public string? GetMetadata(string metadataName) => _keyValuePairs.TryGetValue(metadataName, out string? value) ? value : null;

        public void RemoveMetadata(string metadataName) => throw new NotImplementedException();

        public void SetMetadata(string metadataName, string metadataValue) => throw new NotImplementedException();
    }
}
